﻿namespace DeltaGroup.WheelOfJeopardy.UI.Screens
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows.Controls;
    using System.Windows.Input;

    using DeltaGroup.WheelOfJeopardy.GameManager;
    using DeltaGroup.WheelOfJeopardy.Model;
    using DeltaGroup.WheelOfJeopardy.UI.Events;
    using DeltaGroup.WheelOfJeopardy.UI.ViewModel;

    /// <summary>
    ///     Interaction logic for Game.xaml
    /// </summary>
    public partial class GamePanel : UserControl, INormalRoundUIManager
    {
        #region Fields

        private UserControl _newContent;
        private ScreenTransition _transition;
        private WheelScreen _wheel;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="GamePanel"/> class.
        /// </summary>
        public GamePanel()
        {
            InitializeComponent();
        }

        #endregion Constructors

        #region Events

        /// <summary>
        /// Occurs when [category selected].
        /// </summary>
        public event EventHandler<CategorySelectedEventArgs> CategorySelected;

        /// <summary>
        /// Raised when a contestant has responded to challenge
        /// </summary>
        public event EventHandler<ChallengeResponseReceivedEventArgs> ChallengeResponseReceived;

        /// <summary>
        /// Occurs when [not use free turn].
        /// </summary>
        public event EventHandler NotUseFreeTurn;

        /// <summary>
        /// Raised when a contestant has failed to respond within time allowed
        /// </summary>
        public event EventHandler ResponseTimerExpired;

        /// <summary>
        /// Raised when a sector on Wheel has been selected
        /// </summary>
        public event EventHandler<SectorSelectedEventArgs> SectorSelected;

        /// <summary>
        /// Occurs when [use free turn].
        /// </summary>
        public event EventHandler UseFreeTurn;

        /// <summary>
        /// Occurs when [wager received].
        /// </summary>
        public event EventHandler<WagerReceivedEventArgs> WagerReceived;

        #endregion Events

        #region Properties

        /// <summary>
        /// Gets the name of the contestant.
        /// </summary>
        /// <value>The name of the contestant.</value>
        public string ContestantName
        {
            get
            {
                return (DataContext as NormalRoundViewModel).CurrentContestant.Name;
            }
        }

        /// <summary>
        /// Gets or sets the transition control.
        /// </summary>
        /// <value>The transition control.</value>
        private ScreenTransition TransitionControl
        {
            get
            {
                if (_transition == null)
                {
                    TransitionControl = new ScreenTransition();
                }
                return _transition;
            }
            set
            {
                if (_transition != null)
                {
                    _transition.WipeInCompleted -= new EventHandler(transition_WipeInCompleted);
                    _transition.WipeOutCompleted -= new EventHandler(transition_WipeOutCompleted);
                }

                _transition = value;

                if (_transition != null)
                {
                    _transition.WipeInCompleted += new EventHandler(transition_WipeInCompleted);
                    _transition.WipeOutCompleted += new EventHandler(transition_WipeOutCompleted);
                }
            }
        }

        /// <summary>
        /// Gets the wheel.
        /// </summary>
        /// <value>The wheel.</value>
        private WheelScreen Wheel
        {
            get
            {
                if (_wheel == null)
                {
                    var categories =
                        (DataContext as NormalRoundViewModel).Categories.Select(x => x.Category.Title).ToList();
                    _wheel = new WheelScreen(categories) { DebugMode = (DataContext as NormalRoundViewModel).DebugMode};
                    _wheel.SectorSelected += (sender, args) => RaiseSectorSelected(args.SelectedSector);
                }
                return _wheel;
            }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Prompts for free turn usage.
        /// </summary>
        /// <param name="freeTurnCount">The free turn count.</param>
        public void PromptForFreeTurnUsage(int freeTurnCount)
        {
            var screen = new FreeTurnScreen
                             {
                                 DataContext = new { Remaining = freeTurnCount }
                             };

            ShowContent(screen);
        }

        /// <summary>
        /// Instruct the current contestant to answer
        /// </summary>
        /// <param name="challenge">the challenge to respond to</param>
        /// <param name="secondsAllowed">the time in seconds allowed to respond</param>
        public void PromptForResponse(Challenge challenge, int secondsAllowed)
        {
            var challengeScreen = new ChallengePrompt
                                      {
                                          DataContext = new ChallengePromptViewModel
                                                            {
                                                                Challenge = challenge,
                                                                TimeRemaining = secondsAllowed
                                                            }
                                      };
            challengeScreen.ResponseReceived += (sender, args) => RaiseResponseReceived(args.Response);
            challengeScreen.ResponseTimerExpired += (sender, args) => RaiseResponseTimerExpired();
            ShowContent(challengeScreen);

            challengeScreen.StartTimer();
        }

        /// <summary>
        /// Prompts for wager.
        /// </summary>
        /// <param name="category">The category.</param>
        /// <param name="maxAllowed">The max allowed.</param>
        public void PromptForWager(string category, int maxAllowed)
        {
            var wagerScreen = new WagerScreen
                                  {
                                      DataContext = new WagerModel
                                                        {
                                                            Category = category,
                                                            MaxScore = maxAllowed
                                                        }
                                  };

            ShowContent(wagerScreen);
        }

        /// <summary>
        /// Prompts to select category.
        /// </summary>
        /// <param name="allowedCategories">The allowed categories.</param>
        public void PromptToSelectCategory(List<Category> allowedCategories)
        {
            JeopardyBoard.ShowSelectableCategories(allowedCategories);
        }

        /// <summary>
        /// Instruct the UI to display Wheel to the current player so he can spin
        /// </summary>
        public void PromptToSpin()
        {
            Wheel.Reset();

            ShowContent(Wheel);
        }

        /// <summary>
        /// Raises the sector selected.
        /// </summary>
        /// <param name="sector">The sector.</param>
        public void RaiseSectorSelected(Sector sector)
        {
            if (SectorSelected != null)
                SectorSelected(this, new SectorSelectedEventArgs(sector));
        }

        /// <summary>
        /// Shows the content.
        /// </summary>
        /// <param name="userControl">The user control.</param>
        public void ShowContent(UserControl userControl)
        {
            _newContent = userControl;
            TransitionArea.Content = TransitionControl;
            TransitionControl.WipeIn();
        }

        /// <summary>
        /// Determines whether this instance can exec the specified sender.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void CanExec(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        /// <summary>
        /// Executes the forfeit turn.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void ExecuteForfeitTurn(object sender, ExecutedRoutedEventArgs e)
        {
            if (NotUseFreeTurn != null)
                NotUseFreeTurn(this, EventArgs.Empty);
        }

        /// <summary>
        /// Executes the use free turn.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void ExecuteUseFreeTurn(object sender, ExecutedRoutedEventArgs e)
        {
            if (UseFreeTurn != null)
                UseFreeTurn(this, EventArgs.Empty);
        }

        /// <summary>
        /// Handles the CategorySelected event of the JeopardyBoard control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="DeltaGroup.WheelOfJeopardy.UI.Events.CategorySelectedEventArgs"/> instance containing the event data.</param>
        private void JeopardyBoard_CategorySelected(object sender, CategorySelectedEventArgs e)
        {
            RaiseCategorySelected(e.Category);
        }

        /// <summary>
        /// Raises the category selected.
        /// </summary>
        /// <param name="c">The c.</param>
        private void RaiseCategorySelected(Category c)
        {
            if (CategorySelected != null)
                CategorySelected(this, new CategorySelectedEventArgs(c));
        }

        /// <summary>
        /// Raises the response received.
        /// </summary>
        /// <param name="response">The response.</param>
        private void RaiseResponseReceived(string response)
        {
            ContentArea.Content = null;
            if (ChallengeResponseReceived != null)
                ChallengeResponseReceived(this, new ChallengeResponseReceivedEventArgs(response));
        }

        /// <summary>
        /// Raises the response timer expired.
        /// </summary>
        private void RaiseResponseTimerExpired()
        {
            if (ResponseTimerExpired != null)
                ResponseTimerExpired(this, EventArgs.Empty);
        }

        /// <summary>
        /// Shows the message.
        /// </summary>
        /// <param name="message">The message.</param>
        public void ShowMessage(string message)
        {
            (DataContext as NormalRoundViewModel).Messages.Insert(0, message);
        }

        /// <summary>
        /// Handles the WipeInCompleted event of the transition control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void transition_WipeInCompleted(object sender, EventArgs e)
        {
            ContentArea.Content = _newContent;
        }

        /// <summary>
        /// Handles the WipeOutCompleted event of the transition control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void transition_WipeOutCompleted(object sender, EventArgs e)
        {
            TransitionArea.Content = null;
        }

        /// <summary>
        /// Wagers the specified sender.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void Wager(object sender, ExecutedRoutedEventArgs e)
        {
            if (WagerReceived != null)
                WagerReceived(this, new WagerReceivedEventArgs((int)e.Parameter));
        }

        #endregion Methods
    }
}